package io.kerns.boot.redis;

import io.kerns.core.cache.CacheAdapter;
import lombok.Setter;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;

import java.time.Duration;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * @author xiaohei
 * @create 2020-10-20 下午6:52
 **/
@Setter
public class RedisCacheAdapter implements CacheAdapter {
    private RedisTemplate redisTemplate;

    public <V> void set(String key, V v) {
        redisTemplate.opsForValue().set(key, v);
    }

    public boolean exist(String key) {
        return redisTemplate.hasKey(key);
    }


    @Override
    public Long incr(String key) {
        return redisTemplate.opsForValue().increment(key);
    }


    @Override
    public Set<String> scan(String pattern) {
        return (Set<String>) redisTemplate.execute((RedisCallback<Set<String>>) connection -> {
            Set<String> keysTmp = new HashSet<>();
            try (Cursor<byte[]> cursor = connection.scan(new ScanOptions.ScanOptionsBuilder()
                    .match(pattern)
                    .count(10000).build())) {
                while (cursor.hasNext()) {
                    keysTmp.add(new String(cursor.next(), "Utf-8"));
                }
                return keysTmp;
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        });
    }

    @Override
    public Long decrement(String key) {
        return redisTemplate.opsForValue().decrement(key);
    }

    public <V> V get(String key) {
        return (V) redisTemplate.opsForValue().get(key);
    }

    public <V> void set(String key, V v, Duration duration) {
        redisTemplate.opsForValue().set(key, v, duration);
    }

    public Boolean expire(String key, Duration duration) {
        return redisTemplate.expire(key, duration);
    }

    public Boolean delete(String key) {
        return redisTemplate.delete(key);
    }

    public <H, HK, HV> void addMap(H key, HK hashKey, HV value) {
        redisTemplate.opsForHash().put(key, hashKey, value);
    }

    @Override
    public <H, HK, HV> Map<HK, HV> getMap(H key) {
        return redisTemplate.opsForHash().entries(key);
    }

    @Override
    public <H, HK, HV> Long removeMap(H key, HK... hashKeys) {
        return redisTemplate.opsForHash().delete(key, hashKeys);
    }
}
